Skip to content

nsqd: add Unix domain socket HTTP listener alongside TCP#1528

Open
hwde wants to merge 3 commits into
nsqio:masterfrom
hwde:feature/add-separate-uds-server
Open

nsqd: add Unix domain socket HTTP listener alongside TCP#1528
hwde wants to merge 3 commits into
nsqio:masterfrom
hwde:feature/add-separate-uds-server

Conversation

@hwde

@hwde hwde commented May 27, 2026

Copy link
Copy Markdown

Summary

Adds an optional Unix domain socket HTTP listener to nsqd that runs in
addition to
the regular TCP HTTP listener. Previously it was only possible to
serve HTTP either over TCP or over a unix socket (via --http-address=<path>),
not both at the same time.

New options

  • --unix-socket-path=<path> — if set, nsqd additionally listens for HTTP
    clients on this unix socket. Independent from --http-address.
  • --unix-socket-permission=<octal> — file permission of the socket inode,
    parsed as an octal string (e.g. 0660). Empty means no chmod (umask
    applies).

Both options are opt-in; default behavior is unchanged.

Behavior notes

  • The UDS HTTP server is always served as plain HTTP and ignores
    tls_required. Access control is delegated to filesystem permissions on the
    socket path (that's what --unix-socket-permission is for).
  • If a stale socket file from a previous crashed nsqd is found at the
    configured path, it is removed automatically before Listen. A regular file
    or directory at that path is never removed; nsqd refuses to start
    instead.
  • The process umask is narrowed around net.Listen so the socket inode is
    created with the intended permissions from the start, closing the race window
    between Listen and the follow-up chmod.
  • A RealUDSAddr() accessor is exposed analogous to RealTCPAddr /
    RealHTTPAddr.

Tests

New file nsqd/uds_http_test.go covers:

  • TCP HTTP and UDS HTTP coexist and share NSQD state (/pub over both).
  • Standard endpoints (/ping, /info, /stats) served over UDS.
  • Permission string applied correctly; empty permission falls back to umask.
  • Invalid path and invalid permission string are rejected with an error
    (not a panic).
  • Socket file is removed on clean Exit.
  • Stale socket inode is auto-removed; a non-socket file at the path is
    rejected without being deleted.
  • tls_required is correctly bypassed on the UDS listener.
  • Options default to opt-in ("", "").
  • RealUDSAddr returns the configured path and a zero value when no UDS is
    configured.

All tests pass with and without -race.

Docs

contrib/nsqd.cfg.example has new commented-out entries for both options.

Test plan

  • go build ./...
  • go test ./nsqd -count=1
  • go test ./nsqd -count=1 -race
  • Manual: start nsqd with --unix-socket-path=/tmp/nsqd.sock --unix-socket-permission=0660, publish via curl --unix-socket /tmp/nsqd.sock http://localhost/pub?topic=test -d hello, confirm the
    regular TCP HTTP endpoint still works in parallel.

hwde added 3 commits December 23, 2024 14:40
Add an additional listener for local unix domain sockets. This allows to listen on default http-address, which is used by nsqlookupd.
@atghw

atghw commented Jul 2, 2026

Copy link
Copy Markdown

ready for review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for running an additional HTTP listener over a Unix domain socket (UDS) in nsqd, alongside the existing TCP HTTP listener, including new CLI/config options and tests to validate coexistence and permission behavior.

Changes:

  • Introduces --unix-socket-path and --unix-socket-permission options for an additional UDS HTTP listener.
  • Adds UDS listener creation/serving logic to NSQD plus a RealUDSAddr() accessor.
  • Adds UDS-focused tests and updates the example config with the new settings.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
nsqd/uds_http_test.go Adds tests covering UDS+TCP coexistence, endpoint availability over UDS, permission handling, cleanup, and TLSRequired bypass behavior.
nsqd/options.go Adds option fields for UDS path and permission.
nsqd/nsqd.go Implements the UDS listener lifecycle, permission parsing/application, serving plain HTTP over UDS, and exposes RealUDSAddr().
contrib/nsqd.cfg.example Documents the new config options with commented examples.
apps/nsqd/options.go Exposes the new flags for the nsqd CLI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread nsqd/nsqd.go
"strings"
"sync"
"sync/atomic"
"syscall"
Comment thread nsqd/nsqd.go
Comment on lines +194 to +211
if mode != 0 {
oldMask := syscall.Umask(int(^mode & 0777))
n.udsListener, err = net.Listen("unix", opts.UnixSocketPath)
syscall.Umask(oldMask)
} else {
n.udsListener, err = net.Listen("unix", opts.UnixSocketPath)
}
if err != nil {
return nil, fmt.Errorf("listen (%s) failed - %s", opts.UnixSocketPath, err)
}
if mode != 0 {
// Belt-and-braces: ensure the final mode matches even if the platform
// applied additional restrictions during Listen.
err = os.Chmod(opts.UnixSocketPath, mode)
if err != nil {
return nil, fmt.Errorf("failed to set unix socket permission - %s", err)
}
}
Comment thread nsqd/nsqd.go
// permissions on the socket path (see --unix-socket-permission).
udsHttpServer := newHTTPServer(n, false, false)
n.waitGroup.Wrap(func() {
exitFunc(http_api.Serve(n.udsListener, udsHttpServer, "HTTP", n.logf))
Comment thread nsqd/uds_http_test.go
@@ -0,0 +1,338 @@
package nsqd
Comment thread nsqd/uds_http_test.go
Comment on lines +39 to +47
// wait briefly for Main() to actually start serving on the UDS
deadline := time.Now().Add(2 * time.Second)
for time.Now().Before(deadline) {
if _, err := os.Stat(udsPath); err == nil {
break
}
time.Sleep(10 * time.Millisecond)
}
return httpAddr, udsPath, nsqd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants